#ifndef _JOB_SCHD_H_
#define _JOB_SCHD_H_

#include <unistd.h>
#include <sys/time.h>
#include "ipc_def.h"

#define USAGE_IDENT         "     "
#define SERVER_SOCKET_NAME  "/var/tmp/job_schd"
#define STAT_OUT_FILE       "/var/tmp/job_schd_stat"
#define ARGS_NUM 256
#define MIN_PRIO 0
#define MAX_PRIO 3
#define BUF_SIZE            256
#define SCHD_INTV           10000           /* time(us) slice: 10ms */
#define SC_INTV             100             /* interval(ms) for job's priority change: 100ms */
#define MAX_JOB_NUM         2048
#define BACK_LOG_SIZE       2048            /* used by listen in scheduler */
#define STALE_TIME          30              /* client's name can't be older than this (sec) */
#define ROOT_UID            0

#define TV2MS(tv)         (1000 * (tv).tv_sec + (tv).tv_usec  / 1000)
#define TV2USEC(a, b)       (1000000 * ((b).tv_sec - (a).tv_sec) + (b).tv_usec - (a).tv_usec)
#define TVCLEAR(tv) \
    do { \
        (tv).tv_sec = 0; \
        (tv).tv_usec = 0; \
    } while(0)
#define TVADDUSEC(tv, usec) \
    do { \
        if ((tv).tv_usec + (usec) > 999999) { \
            (tv).tv_sec += 1; \
            (tv).tv_usec = (tv).tv_usec + (usec) - 1000000; \
        } \
        else { \
            (tv).tv_usec += (usec); \
        } \
    } while(0)
#define TAG_TO_ARRAY(tag, array, index) \
    do { \
        (array)[(index)] = malloc((tag).tag_len); \
        memcpy((array)[(index)], (tag).tag_value, (tag).tag_len); \
        (array)[(index)][(tag).tag_len + 1] = '\0'; \
        (index)++; \
    } while(0)
#define FREE_ARRAY(array, size) \
    do { \
        while ((size)--) { \
            free((array)[(size)]); \
        }; \
    } while(0)
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define IS_VALID_PRIOR(p) ((p) < 0 || (p) > 3 ? 0 : (p))

/*
 * bad. if a job is sent a SIGCONT signal then it will
 * start executing himself without profiling present.
 */
typedef enum JobState {
    JS_STOPPED, JS_READY, JS_RUNNING, JS_DONE, JS_EXTRA,
} JobState_t;

typedef struct JobInfo {
    unsigned int    jid;                    /* Job id required by deq. It can the the same as pid but I allocate and reclaim it using alloc_jid and reclaim_jid. */
    pid_t           pid;                    /* Job's id. */
    uid_t           euid;                   /* Effective user id of the job's sender. */
    char            username[BUF_SIZE];     /* Username. */
    unsigned int    argc;
    char            *argv[ARGS_NUM];
    unsigned char   init_prior;             /* Initial priority. */
    unsigned char   curr_prior;             /* Current priority. */
    struct timeval  crea_time;              /* Time created. */
    struct timeval  exec_time;              /* Total executed time. */
    struct timeval  wait_time;              /* Total wait time. */
    struct timeval  cuwa_time;              /* Current accumulated wait time. */
    enum JobState   state;                  /* Current state. */
    struct JobInfo  *prev;
    struct JobInfo  *next;
} JobInfo_t;

extern char *_getlogin(void);
extern void _getusername(uid_t uid, char *buf, unsigned int buf_size);
extern int check_permission(char *fpath, uid_t euid);
extern int init_lisn(void);
extern int init_acpt(int lisnfd, uid_t *uid_p);
extern int init_conn(void);
extern void send_item(int sockfd, unsigned char tag_type, unsigned char tag_len, char *tag_value);
extern int recv_to_buf(int sockfd, unsigned char *buf, unsigned int size);
extern int recv_tag_from_buf(struct tag_struct *tag, unsigned char *base, unsigned char **buf_p);
extern void print_job_info(int outfd, struct JobInfo *job_info);
#endif
